package run.leven.notice.starter.mq;

import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitMessagingTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerContainerFactory;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import run.leven.notice.starter.common.Constants;

import java.util.HashMap;
import java.util.Map;

/**
 * @author leven
 * @date 2020/3/18 21:43
 */
@Configuration
@EnableRabbit
@ConditionalOnClass({RabbitTemplate.class})
public class NoticeProducerAutoConfig {

    @Bean
    @ConditionalOnMissingBean(name = "dlxNoticeTopicExchange")
    public TopicExchange dlxNoticeTopicExchange() {
        return new TopicExchange(Constants.DLX_EXCHANGE);
    }

    @Bean
    @ConditionalOnMissingBean(name = "dlxNoticeEmailQueue")
    public Queue dlxNoticeEmailQueue() {
        return new Queue(Constants.DLX_EMAIL_NOTICE, true, false, false);
    }

    @Bean
    @ConditionalOnMissingBean(name = "dlxNoticeWeChatQueue")
    public Queue dlxNoticeWeChatQueue() {
        return new Queue(Constants.DLX_WE_CHAT_NOTICE, true, false, false);
    }

    @Bean
    @ConditionalOnMissingBean(name = "bindingDlxExchangeEmail")
    @ConditionalOnBean(name = {"dlxNoticeTopicExchange", "dlxNoticeEmailQueue"})
    public Binding bindingDlxExchangeEmail(TopicExchange dlxNoticeTopicExchange, Queue dlxNoticeEmailQueue) {
        return BindingBuilder.bind(dlxNoticeEmailQueue).to(dlxNoticeTopicExchange).with(Constants.DLX_EMAIL_NOTICE);
    }

    @Bean
    @ConditionalOnMissingBean(name = "bindingDlxExchangeWeChat")
    @ConditionalOnBean(name = {"dlxNoticeTopicExchange", "dlxNoticeWeChatQueue"})
    public Binding bindingDlxExchangeWeChat(TopicExchange dlxNoticeTopicExchange, Queue dlxNoticeWeChatQueue) {
        return BindingBuilder.bind(dlxNoticeWeChatQueue).to(dlxNoticeTopicExchange).with(Constants.DLX_WE_CHAT_NOTICE);
    }


    @Bean
    @ConditionalOnMissingBean(name = "noticeTopicExchange")
    public TopicExchange noticeTopicExchange() {
        return new TopicExchange(Constants.NOTICE_EXCHANGE);
    }


    @Bean
    @ConditionalOnMissingBean(name = "noticeEmailQueue")
    @ConditionalOnBean(name = {"bindingDlxExchangeEmail"})
    public Queue noticeEmailQueue() {
        Map<String, Object> arguments = new HashMap<>(16);
        arguments.put("x-dead-letter-exchange", Constants.DLX_EXCHANGE);
        arguments.put("x-dead-letter-routing-key", Constants.DLX_EMAIL_NOTICE);
        return new Queue(Constants.EMAIL_NOTICE, true, false, false, arguments);
    }

    @Bean
    @ConditionalOnMissingBean(name = "noticeWeChatQueue")
    @ConditionalOnBean(name = {"bindingDlxExchangeWeChat"})
    public Queue noticeWeChatQueue() {
        Map<String, Object> arguments = new HashMap<>(16);
        arguments.put("x-dead-letter-exchange", Constants.DLX_EXCHANGE);
        arguments.put("x-dead-letter-routing-key", Constants.DLX_WE_CHAT_NOTICE);
        return new Queue(Constants.WE_CHAT_NOTICE, true, false, false, arguments);
    }

    @Bean
    @ConditionalOnMissingBean(name = "bindingExchangeEmail")
    @ConditionalOnBean(name = {"noticeEmailQueue", "noticeTopicExchange"})
    public Binding bindingExchangeEmail(Queue noticeEmailQueue, TopicExchange noticeTopicExchange) {
        return BindingBuilder.bind(noticeEmailQueue).to(noticeTopicExchange).with(Constants.EMAIL_NOTICE);
    }

    @Bean
    @ConditionalOnMissingBean(name = "bindingExchangeWeChat")
    @ConditionalOnBean(name = {"noticeWeChatQueue", "noticeTopicExchange"})
    public Binding bindingExchangeWeChat(TopicExchange noticeTopicExchange, Queue noticeWeChatQueue) {
        return BindingBuilder.bind(noticeWeChatQueue).to(noticeTopicExchange).with(Constants.WE_CHAT_NOTICE);
    }




    /**
     * rabbit template
     *
     * @param connectionFactory CachingConnectionFactory
     * @param confirmCallBack   ConfirmCallBackListener
     * @param returnCallback    ReturnCallbackListener
     * @return RabbitTemplate
     */
    @Bean
    @ConditionalOnBean(CachingConnectionFactory.class)
    public RabbitTemplate rabbitTemplate(CachingConnectionFactory connectionFactory,
                                         RabbitTemplate.ConfirmCallback confirmCallBack,
                                         RabbitTemplate.ReturnCallback returnCallback) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setConfirmCallback(confirmCallBack);
        rabbitTemplate.setReturnCallback(returnCallback);
        rabbitTemplate.setMandatory(true);
        return rabbitTemplate;
    }

    /**
     * 生产者用
     *
     * @param rabbitTemplate Rabbit Template
     * @return RabbitMessagingTemplate
     */
    @Bean
    public RabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {
        RabbitMessagingTemplate rabbitMessagingTemplate = new RabbitMessagingTemplate();
        rabbitMessagingTemplate.setRabbitTemplate(rabbitTemplate);
        rabbitMessagingTemplate.setMessageConverter(jackson2MessageConverter());
        return rabbitMessagingTemplate;
    }

    @Bean
    public RabbitTemplate.ConfirmCallback confirmCallback() {
        return new ConfirmCallBackListener();
    }

    @Bean
    public RabbitTemplate.ReturnCallback returnCallback() {
        return new ReturnCallbackListener();
    }


    @Bean
    @ConditionalOnMissingBean(MappingJackson2MessageConverter.class)
    @ConditionalOnClass(MappingJackson2MessageConverter.class)
    public MappingJackson2MessageConverter jackson2MessageConverter() {
        return new MappingJackson2MessageConverter();
    }

    @Bean
    public RabbitListenerContainerFactory<?> rabbitListenerContainerFactory(ConnectionFactory connectionFactory){
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(connectionFactory);
        factory.setMessageConverter(new Jackson2JsonMessageConverter());
        return factory;
    }
}
